/**
 * 出参Mock指导增强器
 * 
 * 解决问题：LLM生成UT时经常忽略出参场景，导致测试覆盖率不足
 * 
 * 典型场景：
 * 1. 函数通过引用参数返回数据（vector、map等集合）
 * 2. 后续代码会遍历这些集合
 * 3. 但Mock时只设置了返回值，没有填充出参，导致循环不执行
 */

export class OutParameterMockGuidance {
    
    /**
     * 生成出参Mock指导Prompt
     */
    public static getGuidance(): string {
        return `
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
## 🚨 强制要求：出参Mock（必须正确实现！）
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

### ⚠️ 三大强制规则（违反会导致测试无效）

**规则1：出参必须用SetArgReferee/SetArgPointee填充，禁止只返回ERR_OK**
**规则2：Mock类必须完整定义，禁止使用未定义的Mock类**
**规则3：必须包含所需的头文件，包括mock.h**

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
## ⚠️ 关键测试场景：出参Mock（常被忽略！）
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

### 📊 问题场景识别

如果被测代码有以下模式，**必须测试出参不为空的场景**：

\`\`\`cpp
// 模式1：集合作为出参，后续有遍历
std::vector<int64_t> dataList;
int32_t ret = service->GetDataList(dataList);  // dataList是出参
for (auto data : dataList) {  // ⚠️ 需要测试这里！
    // 重要的业务逻辑
}

// 模式2：引用参数返回数据
std::map<string, string> resultMap;
bool success = service->FetchData(resultMap);  // resultMap是出参
if (resultMap.find("key") != resultMap.end()) {  // ⚠️ 需要测试这里！
    // 使用返回的数据
}

// 模式3：指针参数返回数据
DataStruct* output = nullptr;
int32_t ret = service->Process(&output);  // output是出参
if (output != nullptr) {  // ⚠️ 需要测试这里！
    // 使用output
}
\`\`\`

### ❌ 错误的Mock方式（会导致测试覆盖不足）

\`\`\`cpp
TEST_F(ServiceTest, TestGetDataList_Wrong) {
    std::vector<int64_t> dataList;
    
    // ❌ 错误：只Mock了返回值，没有填充出参
    EXPECT_CALL(*mockService, GetDataList(_))
        .WillOnce(Return(ERR_OK));
    
    int32_t ret = mockService->GetDataList(dataList);
    EXPECT_EQ(ret, ERR_OK);
    
    // ⚠️ 问题：dataList仍然是空的！
    // 后续的 for (auto data : dataList) 不会执行
    // 导致循环内的代码没有被测试！
}
\`\`\`

### ✅ 正确的Mock方式（覆盖出参场景）

**🚨 重要：生成测试代码时，必须按照以下顺序完成：**

1. **第一步：包含必需的头文件**
2. **第二步：定义Mock类（如果需要）**
3. **第三步：使用SetArgReferee/SetArgPointee填充出参**

#### 完整示例：正确的测试代码结构

\`\`\`cpp
// ========== 第一步：包含必需的头文件 ==========
#include <gtest/gtest.h>
#include <gmock/gmock.h>

// 必须包含被测类的头文件
#include "your_service.h"

// 必须包含测试工具头文件
using testing::SetArgReferee;  // ⚠️ 填充引用参数必需
using testing::SetArgPointee;  // ⚠️ 填充指针参数必需
using testing::DoAll;
using testing::Return;
using testing::_;

// ========== 第二步：定义Mock类（如果原类是虚类或接口）==========
// ⚠️ 注意：只有在被Mock的类有虚函数时才需要定义Mock类
class MockYourService : public YourService {
public:
    MOCK_METHOD(int32_t, GetDataList, (std::vector<int64_t>& outList), (override));
    // 其他需要Mock的虚函数...
};

// ========== 第三步：编写测试用例，正确使用SetArgReferee ==========
class ServiceTest : public testing::Test {
protected:
    void SetUp() override {
        mockService_ = std::make_shared<MockYourService>();
    }
    
    void TearDown() override {
        mockService_ = nullptr;
    }
    
    std::shared_ptr<MockYourService> mockService_;
};

TEST_F(ServiceTest, TestGetDataList_WithData_Correct) {
    std::vector<int64_t> dataList;
    
    // ✅ 正确：使用SetArgReferee填充出参（引用类型）
    EXPECT_CALL(*mockService_, GetDataList(_))
        .WillOnce(DoAll(
            SetArgReferee<0>(std::vector<int64_t>{123, 456, 789}),  // 填充vector
            Return(ERR_OK)
        ));
    
    int32_t ret = mockService_->GetDataList(dataList);
    
    // 验证返回值
    EXPECT_EQ(ret, ERR_OK);
    
    // ✅ 验证出参被正确填充
    EXPECT_EQ(dataList.size(), 3);
    EXPECT_EQ(dataList[0], 123);
    EXPECT_EQ(dataList[1], 456);
    EXPECT_EQ(dataList[2], 789);
    
    // ✅ 现在可以测试遍历逻辑了
    // 原函数中的 for (auto data : dataList) 会执行3次
}
\`\`\`

**🚨 常见错误对比：**

\`\`\`cpp
// ❌ 错误1：没有包含SetArgReferee
// 编译错误：'SetArgReferee' is not a member of 'testing'

// ❌ 错误2：使用了未定义的Mock类
auto mockService = std::make_shared<MockYourService>();  // 编译错误
// 必须先定义 class MockYourService : public YourService {...}

// ❌ 错误3：只返回ERR_OK，没有填充出参
EXPECT_CALL(*mock, GetDataList(_))
    .WillOnce(Return(ERR_OK));  // dataList仍然是空的！

// ✅ 正确：使用DoAll同时填充出参和返回值
EXPECT_CALL(*mock, GetDataList(_))
    .WillOnce(DoAll(
        SetArgReferee<0>(std::vector<int64_t>{1, 2, 3}),
        Return(ERR_OK)
    ));
\`\`\`

#### 方式2：使用SetArgPointee（指针参数）

\`\`\`cpp
using testing::SetArgPointee;

TEST_F(ServiceTest, TestProcess_WithOutput_Correct) {
    DataStruct* output = nullptr;
    
    // ✅ 正确：使用SetArgPointee填充出参（指针类型）
    DataStruct mockData;
    mockData.id = 100;
    mockData.name = "test";
    
    EXPECT_CALL(*mockService, Process(_))
        .WillOnce(DoAll(
            SetArgPointee<0>(mockData),  // 填充指针指向的数据
            Return(ERR_OK)
        ));
    
    int32_t ret = mockService->Process(&output);
    
    EXPECT_EQ(ret, ERR_OK);
    EXPECT_NE(output, nullptr);  // ✅ 验证指针不为空
    EXPECT_EQ(output->id, 100);  // ✅ 验证数据正确
}
\`\`\`

#### 方式3：使用Lambda自定义行为

\`\`\`cpp
using testing::Invoke;

TEST_F(ServiceTest, TestFetchData_WithMap_Correct) {
    std::map<string, string> resultMap;
    
    // ✅ 正确：使用Invoke自定义填充逻辑
    EXPECT_CALL(*mockService, FetchData(_))
        .WillOnce(Invoke([](std::map<string, string>& outMap) {
            outMap["userId"] = "12345";
            outMap["bundleName"] = "com.example.app";
            outMap["appIndex"] = "0";
            return true;
        }));
    
    bool success = mockService->FetchData(resultMap);
    
    EXPECT_TRUE(success);
    EXPECT_EQ(resultMap.size(), 3);  // ✅ 验证map被填充
    EXPECT_EQ(resultMap["userId"], "12345");
    
    // ✅ 现在可以测试后续的查找和处理逻辑
}
\`\`\`

### 🎯 SetArgReferee参数索引说明

\`\`\`cpp
// 函数签名：
int32_t GetData(int32_t id, std::vector<int64_t>& outList, const string& filter);
//               ↑ 参数0      ↑ 参数1（出参）              ↑ 参数2

// Mock时：
EXPECT_CALL(*mock, GetData(_, _, _))
    .WillOnce(DoAll(
        SetArgReferee<1>(std::vector<int64_t>{1, 2, 3}),  // 填充参数1
        Return(ERR_OK)
    ));

// 参数索引从0开始：
// 参数0 = id
// 参数1 = outList（这是我们要填充的）
// 参数2 = filter
\`\`\`

### 📋 真实示例：BundleObserver::HandleBundleBroadcast

#### ❌ 错误的测试（当前生成的）

\`\`\`cpp
TEST_F(BundleObserverTest, HandleBundleBroadcast_001) {
    auto saMgrPtr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
    
    // ❌ 问题：只Mock返回值，extraDataIdList是空的
    EXPECT_CALL(*saMgrPtr, GetCommonEventExtraDataIdlist(SA_ID, _, _))
        .WillOnce(Return(ERR_OK));
    
    int32_t result = observer_->HandleBundleBroadcast();
    EXPECT_EQ(result, ERR_OK);
    
    // ⚠️ 问题：原函数中的 for (auto dataId : extraDataIdList) 不会执行
    // 导致 GetOnDemandReasonExtraData、ClearSyncFolder 等逻辑没有被测试！
}
\`\`\`

#### ✅ 正确的测试（应该生成的）

\`\`\`cpp
// ========== 必须的头文件 ==========
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include "bundle_observer.h"

using testing::SetArgReferee;  // ⚠️ 必须包含！
using testing::DoAll;
using testing::Return;
using testing::_;

// ========== Mock类定义（如果SystemAbilityManager有虚函数需要Mock）==========
// 注意：如果使用真实的SystemAbilityManager不需要Mock，这里只是示例
// 实际项目中检查是否已有Mock类，如有则引入其头文件

/**
 * @tc.number: BundleObserver_HandleBundleBroadcast_005
 * @tc.name: HandleBundleBroadcast with multiple extraDataIds
 * @tc.desc: Verify HandleBundleBroadcast processes multiple data correctly
 */
TEST_F(BundleObserverTest, BundleObserver_HandleBundleBroadcast_005) {
    GTEST_LOG_(INFO) << "BundleObserverTest-begin BundleObserver_HandleBundleBroadcast_005";
    
    auto saMgrPtr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
    ASSERT_NE(saMgrPtr, nullptr);
    
    // ✅ 正确：使用SetArgReferee填充出参 extraDataIdList
    // 参数索引：0=SA_ID, 1=extraDataIdList（出参）, 2=eventType
    EXPECT_CALL(*saMgrPtr, GetCommonEventExtraDataIdlist(
        SA_ID, 
        _, 
        EventFwk::CommonEventSupport::COMMON_EVENT_PACKAGE_REMOVED))
        .WillOnce(DoAll(
            SetArgReferee<1>(std::vector<int64_t>{100, 200, 300}),  // ⚠️ 填充3个dataId
            Return(ERR_OK)
        ));
    
    // ✅ Mock每个dataId的GetOnDemandReasonExtraData调用
    // 预期会调用3次（对应上面填充的3个dataId）
    
    // 第1个dataId的Mock
    EXPECT_CALL(*saMgrPtr, GetOnDemandReasonExtraData(100, _))
        .WillOnce(DoAll(
            testing::Invoke([](int64_t id, MessageParcel& parcel) {
                // 填充MessageParcel数据
                parcel.WriteString("userId:123");
                parcel.WriteString("bundleName:com.test.app1");
                parcel.WriteString("appIndex:0");
            }),
            Return(ERR_OK)
        ));
    
    // 第2个dataId的Mock
    EXPECT_CALL(*saMgrPtr, GetOnDemandReasonExtraData(200, _))
        .WillOnce(DoAll(
            testing::Invoke([](int64_t id, MessageParcel& parcel) {
                parcel.WriteString("userId:456");
                parcel.WriteString("bundleName:com.test.app2");
                parcel.WriteString("appIndex:1");
            }),
            Return(ERR_OK)
        ));
    
    // 第3个dataId的Mock
    EXPECT_CALL(*saMgrPtr, GetOnDemandReasonExtraData(300, _))
        .WillOnce(DoAll(
            testing::Invoke([](int64_t id, MessageParcel& parcel) {
                parcel.WriteString("userId:789");
                parcel.WriteString("bundleName:com.test.app3");
                parcel.WriteString("appIndex:2");
            }),
            Return(ERR_OK)
        ));
    
    // Mock ClearSyncFolder（会被调用3次）
    EXPECT_CALL(*fileAccessService_, UnregisterAllByBundle(_, _, _))
        .Times(3)
        .WillRepeatedly(Return(ERR_OK));
    
    // Act
    int32_t result = observer_->HandleBundleBroadcast();
    
    // Assert
    EXPECT_EQ(result, ERR_OK);
    
    GTEST_LOG_(INFO) << "BundleObserverTest-end BundleObserver_HandleBundleBroadcast_005";
}
\`\`\`

**🚨 对比错误的生成：**

\`\`\`cpp
// ❌ 用户反馈的错误示例
TEST_F(BundleObserverTest, BundleObserver_HandleBundleBroadcast_001) {
    // ❌ 错误1：使用了未定义的Mock类
    auto mockSaManager = std::make_shared<MockSystemAbilityManager>();  // 编译失败！
    
    // ❌ 错误2：没有使用SetArgReferee填充extraDataIdList
    EXPECT_CALL(*mockSaManager, GetCommonEventExtraDataIdlist(SA_ID, _, _))
        .WillOnce(Return(ERR_OK));  // extraDataIdList仍然是空的！
    
    // ❌ 结果：for (auto dataId : extraDataIdList) 不会执行
    // 导致GetOnDemandReasonExtraData、ClearSyncFolder等逻辑完全没有测试
}
\`\`\`

### 🎯 测试用例设计清单（出参场景）

针对有出参的函数，必须设计以下测试用例：

- [ ] **空集合场景**：出参为空（size = 0），验证循环不执行或有默认处理
- [ ] **单元素场景**：出参有1个元素，验证基本处理逻辑
- [ ] **多元素场景**：出参有多个元素（3-5个），验证遍历和批处理逻辑
- [ ] **边界场景**：出参有大量元素（如100个），验证性能和边界处理
- [ ] **异常数据场景**：出参包含nullptr、空字符串等异常数据

### 🔍 如何识别需要Mock出参的函数

在被测代码中查找以下模式：

1. **引用参数 + 后续使用**
   \`\`\`cpp
   void GetData(std::vector<T>& output);  // 引用参数
   // 后续：for (auto item : output) { ... }
   \`\`\`

2. **指针参数 + nullptr检查**
   \`\`\`cpp
   int Process(Data** output);  // 指针的指针
   // 后续：if (output != nullptr) { ... }
   \`\`\`

3. **容器参数 + size()检查**
   \`\`\`cpp
   bool Fetch(std::map<K, V>& result);
   // 后续：if (result.size() > 0) { ... }
   \`\`\`

4. **读取Parcel**
   \`\`\`cpp
   int GetExtraData(int64_t id, MessageParcel& parcel);
   // 后续：auto data = parcel.ReadParcelable<T>();
   \`\`\`

### 📝 生成UT时的强制要求

1. ✅ **分析函数调用的参数类型**，识别引用和指针参数
2. ✅ **检查函数后续代码**，看是否有遍历、size()检查、nullptr检查
3. ✅ **如果有遍历或检查**，必须生成"非空场景"的测试用例
4. ✅ **使用SetArgReferee或SetArgPointee**填充出参
5. ✅ **验证出参内容**，确保填充正确
6. ✅ **测试用例命名要体现出参场景**，如 \`_WithMultipleData\`、\`_WithNonEmptyList\`

### 🚨 代码生成前的强制自检清单

在生成任何测试代码之前，必须确认以下每一项：

\`\`\`
□ 1. 头文件检查
   - [ ] 包含了 <gtest/gtest.h>
   - [ ] 包含了 <gmock/gmock.h>
   - [ ] 包含了 using testing::SetArgReferee;（如果有引用出参）
   - [ ] 包含了 using testing::SetArgPointee;（如果有指针出参）
   - [ ] 包含了 using testing::DoAll;
   - [ ] 包含了 using testing::Return;

□ 2. Mock类检查
   - [ ] 如果需要Mock类，是否已经定义？
   - [ ] Mock类的定义是否在测试文件开头？
   - [ ] Mock类是否正确继承了基类？
   - [ ] Mock类是否使用了MOCK_METHOD宏？
   - [ ] 如果项目已有Mock类，是否包含了对应的mock.h头文件？

□ 3. 出参填充检查
   - [ ] 是否识别出了函数的出参（引用或指针参数）？
   - [ ] 是否使用了SetArgReferee或SetArgPointee填充出参？
   - [ ] 参数索引是否正确？（从0开始计数）
   - [ ] 是否使用了DoAll同时设置出参和返回值？
   - [ ] 填充的数据是否有实际意义（不是空集合）？

□ 4. 测试逻辑检查
   - [ ] 是否验证了出参被正确填充？（如 EXPECT_EQ(list.size(), 3)）
   - [ ] 是否覆盖了遍历逻辑？（如果原函数有for循环）
   - [ ] 是否Mock了循环内会调用的函数？
   - [ ] Mock的调用次数是否正确？（如 .Times(3)）
\`\`\`

### 🚨 常见错误速查表

| 错误现象 | 原因 | 解决方法 |
|---------|------|---------|
| 编译错误：'SetArgReferee' is not a member of 'testing' | 没有包含头文件 | 添加 \`using testing::SetArgReferee;\` |
| 编译错误：'MockXXX' was not declared | Mock类未定义 | 在测试文件开头定义Mock类或包含mock.h |
| 测试运行但循环逻辑未覆盖 | 出参未填充，集合为空 | 使用 \`SetArgReferee<N>(具体数据)\` |
| Mock函数未被调用 | 参数索引错误或DoAll顺序错误 | 检查参数索引和DoAll顺序 |
| 测试失败：Unexpected function call | Mock次数不匹配 | 使用 \`.Times(N)\` 或 \`.WillRepeatedly()\` |

### ✅ 正确代码模板（直接复制使用）

\`\`\`cpp
// ========== 头文件部分 ==========
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include "your_class.h"  // 被测类

using testing::SetArgReferee;
using testing::DoAll;
using testing::Return;
using testing::_;

// ========== Mock类部分（如果需要）==========
class MockYourClass : public YourClass {
public:
    MOCK_METHOD(int32_t, YourMethod, (int param1, std::vector<int>& outParam), (override));
};

// ========== 测试类部分 ==========
class YourTest : public testing::Test {
protected:
    void SetUp() override {
        instance_ = std::make_shared<MockYourClass>();
    }
    
    std::shared_ptr<MockYourClass> instance_;
};

// ========== 测试用例部分 ==========
TEST_F(YourTest, TestWithOutParam_MultipleData) {
    // Arrange: 准备测试数据
    std::vector<int> outData;
    
    // Act & Assert: Mock出参
    EXPECT_CALL(*instance_, YourMethod(_, _))
        .WillOnce(DoAll(
            SetArgReferee<1>(std::vector<int>{1, 2, 3}),  // 填充出参
            Return(ERR_OK)
        ));
    
    int32_t result = instance_->YourMethod(123, outData);
    
    // Verify
    EXPECT_EQ(result, ERR_OK);
    EXPECT_EQ(outData.size(), 3);  // 验证出参
    EXPECT_EQ(outData[0], 1);
}
\`\`\`

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
`;
    }
    
    /**
     * 精准分析代码中是否有需要SetArgReferee的出参场景
     * 
     * 触发条件（基于251,823个真实UT函数的0.42%使用率分析）：
     * 1. 检测到容器引用/指针参数
     * 2. 该参数被传递给被Mock的函数
     * 3. 该参数在后续代码中被遍历或访问
     * 
     * 精准识别能减少开发者改动！
     */
    public static analyzeOutParameters(code: string): {
        hasOutParams: boolean;
        hasVectorOut: boolean;
        hasMapOut: boolean;
        hasPointerOut: boolean;
        hasLoopAfterCall: boolean;
        outParamPatterns: string[];
        outParamNames: string[];  // 新增：提取出的参数名
        confidence: 'high' | 'medium' | 'low';  // 新增：置信度
    } {
        const patterns = [];
        const outParamNames: string[] = [];
        let confidence: 'high' | 'medium' | 'low' = 'low';
        
        // 检测vector/list作为出参，并提取变量名
        const vectorPattern = /(?:std::)?(?:vector|list)<[^>]+>\s*&\s*(\w+)/g;
        let match;
        while ((match = vectorPattern.exec(code)) !== null) {
            outParamNames.push(match[1]);
            patterns.push(`vector/list& ${match[1]}`);
        }
        const hasVectorOut = outParamNames.length > 0;
        
        // 检测map作为出参，并提取变量名
        const mapPattern = /(?:std::)?map<[^>]+>\s*&\s*(\w+)/g;
        while ((match = mapPattern.exec(code)) !== null) {
            outParamNames.push(match[1]);
            patterns.push(`map& ${match[1]}`);
        }
        const hasMapOut = /map<[^>]+>\s*&\s*\w+/.test(code);
        
        // 检测指针作为出参
        const pointerPattern = /(\w+)\s*\*\s*(&\s*)?(\w+)(?=\s*[,)])/g;
        while ((match = pointerPattern.exec(code)) !== null) {
            // 过滤掉基础类型指针
            const typeName = match[1];
            if (!['int', 'char', 'void', 'bool', 'double', 'float', 'uint8_t', 'uint32_t', 'int32_t'].includes(typeName)) {
                outParamNames.push(match[3]);
                patterns.push(`${typeName}* ${match[3]}`);
            }
        }
        const hasPointerOut = /\*\s*&\s*\w+|\*\*\s*\w+/.test(code);
        
        // 【关键】精准检测：这些出参变量是否在后续被遍历或访问
        let hasLoopAfterCall = false;
        if (outParamNames.length > 0) {
            for (const paramName of outParamNames) {
                // 1. Range-based for循环：for (auto x : paramName)
                const rangeForRegex = new RegExp(`for\\s*\\([^)]*:\\s*${paramName}\\s*\\)`, 'g');
                if (rangeForRegex.test(code)) {
                    hasLoopAfterCall = true;
                    confidence = 'high';  // 明确的遍历信号
                    break;
                }
                
                // 2. Iterator使用：paramName.begin(), paramName.end()
                const iteratorRegex = new RegExp(`${paramName}\\s*\\.\\s*(begin|end|rbegin|rend)\\s*\\(`, 'g');
                if (iteratorRegex.test(code)) {
                    hasLoopAfterCall = true;
                    confidence = 'high';
                    break;
                }
                
                // 3. Size检查：if (!paramName.empty()) 或 for(i=0; i<paramName.size(); i++)
                const sizeRegex = new RegExp(`${paramName}\\s*\\.\\s*(size|empty)\\s*\\(`, 'g');
                if (sizeRegex.test(code)) {
                    hasLoopAfterCall = true;
                    if (confidence === 'low') {
                        confidence = 'medium';  // size()可能只是检查
                    }
                }
                
                // 4. 下标访问：paramName[i] 或 paramName.at(i)
                const indexRegex = new RegExp(`${paramName}\\s*\\[|${paramName}\\s*\\.\\s*at\\s*\\(`, 'g');
                if (indexRegex.test(code)) {
                    hasLoopAfterCall = true;
                    if (confidence === 'low') {
                        confidence = 'medium';
                    }
                }
            }
        }
        
        // 兜底：通用检测
        if (!hasLoopAfterCall) {
            hasLoopAfterCall = /for\s*\([^)]*:\s*\w+\)|while\s*\([^)]*\.size\(\)|if\s*\([^)]*\.empty\(\)/.test(code);
            if (hasLoopAfterCall && confidence === 'low') {
                confidence = 'low';  // 通用检测的置信度较低
            }
        }
        
        const hasOutParams = hasVectorOut || hasMapOut || hasPointerOut;
        
        return {
            hasOutParams,
            hasVectorOut,
            hasMapOut,
            hasPointerOut,
            hasLoopAfterCall,
            outParamPatterns: patterns,
            outParamNames,
            confidence
        };
    }
}

